﻿namespace Microsoft.VisualStudio.ServiceModel.DomainServices.Tools
{
    using EnvDTE;
    using EnvDTE80;
    using Microsoft.ServiceModel.DomainServices.Tools;
    using Microsoft.VisualStudio.ManagedInterfaces9;
    using Microsoft.VisualStudio.OLE.Interop;
    using Microsoft.VisualStudio.Shell;
    using Microsoft.VisualStudio.Shell.Design;
    using Microsoft.VisualStudio.Shell.Interop;
    using Microsoft.VisualStudio.TemplateWizard;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Design;
    using System.Configuration;
    using System.Data.Linq;
    using System.Data.Objects;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Threading;
    using System.Windows.Forms;
    using System.Windows.Forms.Design;
    using System.Windows.Interop;
    using VSLangProj;

    internal class DomainServiceClassWizard : IWizard
    {
        private GeneratedCode _businessLogicCode;
        private BusinessLogicClassDialog _dialog;
        private EnvDTE80.DTE2 _dte2;
        private bool _generateMetadataFile;
        private bool _isClientAccessEnabled;
        private bool _isODataEndpointEnabled;
        private GeneratedCode _metadataCode;
        private Project _project;
        private InternalTestHook _testHook;

        private void AddReferences(IEnumerable<string> references)
        {
            if (references.Any<string>())
            {
                VSProject project2 = this.ActiveProject.Object as VSProject;
                if (project2 != null)
                {
                    foreach (string str in references)
                    {
                        Reference reference = project2.References.Add(str);
                        if (ShouldCopyLocal(str))
                        {
                            reference.CopyLocal = true;
                        }
                    }
                }
            }
        }

        public void BeforeOpeningFile(ProjectItem projectItem)
        {
        }

        private string ComputeNamespace()
        {
            ProjectItems projItems = null;
            if (this._dte2.SelectedItems.Count == 1)
            {
                SelectedItem item = this._dte2.SelectedItems.Item(1);
                if (item.ProjectItem != null)
                {
                    projItems = item.ProjectItem.ProjectItems;
                    if ((projItems != null) && (projItems.Kind != "{6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}"))
                    {
                        projItems = null;
                    }
                }
            }
            if (projItems == null)
            {
                projItems = this.ActiveProject.ProjectItems;
            }
            return FindNSOfItem(projItems);
        }

        private static string FindNSOfItem(ProjectItems projItems)
        {
            string extension = Path.GetExtension(projItems.ContainingProject.FileName);
            if (!string.Equals(extension, ".csproj", StringComparison.OrdinalIgnoreCase) && !string.Equals(extension, ".vjsproj", StringComparison.OrdinalIgnoreCase))
            {
                if (projItems.ContainingProject.Object is VSProject)
                {
                    return projItems.ContainingProject.Properties.Item("RootNamespace").Value.ToString();
                }
                return MakeNameCompliant(Path.GetFileNameWithoutExtension(projItems.ContainingProject.FileName));
            }
            if (projItems is Project)
            {
                return projItems.ContainingProject.Properties.Item("RootNamespace").Value.ToString();
            }
            string str2 = string.Empty;
            while (projItems.Kind == "{6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}")
            {
                if (projItems.Parent is Project)
                {
                    if (str2.Length == 0)
                    {
                        return projItems.ContainingProject.Properties.Item("RootNamespace").Value.ToString();
                    }
                    return (projItems.ContainingProject.Properties.Item("RootNamespace").Value.ToString() + "." + str2);
                }
                if (str2.Length == 0)
                {
                    str2 = MakeNameCompliant(((ProjectItem) projItems.Parent).Name);
                }
                else
                {
                    str2 = MakeNameCompliant(((ProjectItem) projItems.Parent).Name) + "." + str2;
                }
                projItems = ((ProjectItem) projItems.Parent).Collection;
            }
            return str2;
        }

        private IEnumerable<System.Type> GetCandidateTypes(ITypeDiscoveryService typeDiscoveryService)
        {
            List<System.Type> list = new List<System.Type>();
            VSProject vsProject = this.ActiveProject.Object as VSProject;
            if ((vsProject != null) && (typeDiscoveryService != null))
            {
                List<Reference> projectReferences = new List<Reference>();
                foreach (Reference reference in vsProject.References)
                {
                    if (((reference != null) && !string.IsNullOrEmpty(reference.Name)) && (reference.Type == prjReferenceType.prjReferenceTypeAssembly))
                    {
                        projectReferences.Add(reference);
                    }
                }
                bool enableDataContextTypes = LinqToSqlContext.EnableDataContextTypes;
                foreach (System.Type type in typeDiscoveryService.GetTypes(typeof(object), true))
                {
                    if (IsContextType(type, enableDataContextTypes) && IsVisibleInCurrentProject(type, vsProject, projectReferences))
                    {
                        list.Add(type);
                    }
                }
            }
            return list;
        }

        private object GetService(System.Type serviceType)
        {
            Microsoft.VisualStudio.OLE.Interop.IServiceProvider sp = this.DTE2 as Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
            if (sp == null)
            {
                return null;
            }
            using (ServiceProvider provider2 = new ServiceProvider(sp))
            {
                return provider2.GetService(serviceType);
            }
        }

        private ITypeDiscoveryService GetTypeDiscoveryService(Project project)
        {
            DynamicTypeService service = this.GetService(typeof(DynamicTypeService)) as DynamicTypeService;
            if (service == null)
            {
                return null;
            }
            IVsHierarchy vsHierarchy = this.GetVsHierarchy(project);
            return service.GetTypeDiscoveryService(vsHierarchy);
        }

        private IVsHierarchy GetVsHierarchy(Project project)
        {
            IVsSolution service = this.GetService(typeof(SVsSolution)) as IVsSolution;
            if (service == null)
            {
                this.TerminateWizard(Resources.BusinessLogicClass_Error_No_Hierarchy);
            }
            IVsHierarchy ppHierarchy = null;
            if ((service.GetProjectOfUniqueName(project.UniqueName, out ppHierarchy) != 0) || (ppHierarchy == null))
            {
                this.TerminateWizard(Resources.BusinessLogicClass_Error_No_Hierarchy);
            }
            return ppHierarchy;
        }

        private static bool IsAssociatedMetadataFile(string fileName)
        {
            return (fileName.IndexOf(".metadata.", StringComparison.OrdinalIgnoreCase) >= 0);
        }

        internal static bool IsContextType(System.Type t, bool dataContextEnabled)
        {
            if ((t.IsValueType || t.IsInterface) || ((!typeof(ObjectContext).IsAssignableFrom(t) && !t.IsDbContext()) && (!dataContextEnabled || !typeof(DataContext).IsAssignableFrom(t))))
            {
                return false;
            }
            return true;
        }

        private static bool IsVisibleInCurrentProject(System.Type t, VSProject vsProject, IEnumerable<Reference> projectReferences)
        {
            if (((t == null) || (vsProject == null)) || (projectReferences == null))
            {
                return true;
            }
            Assembly assembly = t.Assembly;
            string name = assembly.GetName().Name;
            Project project = vsProject.Project;
            string str2 = (string) project.Properties.Item("AssemblyName").Value;
            if (name.Equals(str2, StringComparison.Ordinal))
            {
                return true;
            }
            string str3 = project.ConfigurationManager.ActiveConfiguration.Properties.Item("IntermediatePath").Value as string;
            string str4 = Path.Combine(Path.GetDirectoryName(project.FullName), str3);
            if (assembly.Location.StartsWith(str4, StringComparison.OrdinalIgnoreCase))
            {
                return true;
            }
            foreach (Reference reference in projectReferences)
            {
                string identity = reference.Identity;
                if (identity.EndsWith(char.ToString('\0'), StringComparison.Ordinal))
                {
                    identity = identity.Substring(0, identity.Length - 1);
                }
                if (identity.Equals(name, StringComparison.OrdinalIgnoreCase))
                {
                    return true;
                }
            }
            return false;
        }

        private static string MakeNameCompliant(string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                return string.Empty;
            }
            if (char.IsDigit(name[0]))
            {
                name = "_" + name;
            }
            for (int i = 0; i < name.Length; i++)
            {
                UnicodeCategory unicodeCategory = char.GetUnicodeCategory(name[i]);
                if (((((unicodeCategory != UnicodeCategory.UppercaseLetter) && (unicodeCategory != UnicodeCategory.LowercaseLetter)) && ((unicodeCategory != UnicodeCategory.OtherLetter) && (unicodeCategory != UnicodeCategory.ConnectorPunctuation))) && (((unicodeCategory != UnicodeCategory.ModifierLetter) && (unicodeCategory != UnicodeCategory.NonSpacingMark)) && ((unicodeCategory != UnicodeCategory.SpacingCombiningMark) && (unicodeCategory != UnicodeCategory.TitlecaseLetter)))) && ((((unicodeCategory != UnicodeCategory.Format) && (unicodeCategory != UnicodeCategory.LetterNumber)) && ((unicodeCategory != UnicodeCategory.DecimalDigitNumber) && (name[i] != '.'))) && (name[i] != '_')))
                {
                    name = name.Replace(name[i], '_');
                }
            }
            return name;
        }

        public void ProjectFinishedGenerating(Project project)
        {
        }

        public void ProjectItemFinishedGenerating(ProjectItem projectItem)
        {
        }

        public void RunFinished()
        {
            this.UpdateConfiguration();
        }

        public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
        {
            Action<Exception> action = null;
            this._project = null;
            this._dte2 = automationObject as EnvDTE80.DTE2;
            if (this._dte2 == null)
            {
                this.TerminateWizard(Resources.WizardError_No_DTE);
            }
            Project activeProject = this.ActiveProject;
            ITypeDiscoveryService typeDiscoveryService = this.GetTypeDiscoveryService(activeProject);
            if (typeDiscoveryService == null)
            {
                this.TerminateWizard(Resources.BusinessLogicClass_Error_No_TypeDiscoveryService);
            }
            IEnumerable<System.Type> candidateTypes = this.GetCandidateTypes(typeDiscoveryService);
            string str = replacementsDictionary["$rootname$"];
            str = str.Trim();
            if (string.IsNullOrEmpty(str))
            {
                this.TerminateWizard(Resources.WizardError_Empty_Filename);
            }
            string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(str);
            if (string.IsNullOrEmpty(fileNameWithoutExtension))
            {
                this.TerminateWizard(Resources.WizardError_Empty_Filename);
            }
            bool flag = Path.GetExtension(str).EndsWith("vb", StringComparison.OrdinalIgnoreCase);
            string language = flag ? "VB" : "C#";
            Property property = activeProject.Properties.Item("RootNamespace");
            string str5 = (property == null) ? null : ((string) property.Value);
            if (string.IsNullOrEmpty(str5))
            {
                this.TerminateWizard(Resources.BusinessLogicClass_Error_No_RootNamespace);
            }
            string rootNamespace = flag ? str5 : string.Empty;
            Property property2 = activeProject.Properties.Item("AssemblyName");
            string str7 = (property2 == null) ? null : ((string) property2.Value);
            if (string.IsNullOrEmpty(str7))
            {
                this.TerminateWizard(Resources.BusinessLogicClass_Error_No_AssemblyName);
            }
            IEnumerable<System.Type> contextTypes = from t in candidateTypes
                where CodeGenUtilities.IsValidGenericTypeParam(t)
                select t;
            string fullName = activeProject.FullName;
            if (string.IsNullOrEmpty(fullName))
            {
                this.TerminateWizard(Resources.BusinessLogicClass_No_Project_Path);
            }
            string directoryName = Path.GetDirectoryName(fullName);
            try
            {
                IVsHelp service = this.GetService(typeof(IVsHelp)) as IVsHelp;
                using (BusinessLogicViewModel model = new BusinessLogicViewModel(directoryName, fileNameWithoutExtension, language, rootNamespace, str7, contextTypes, service))
                {
                    if (action == null)
                    {
                        action = delegate (Exception ex) {
                            this.ShowError(ex.Message);
                            throw ex;
                        };
                    }
                    model.ExceptionHandler = action;
                    this._dialog = new BusinessLogicClassDialog();
                    this._dialog.Model = model;
                    IVsUIShell shell = this.GetService(typeof(IVsUIShell)) as IVsUIShell;
                    IntPtr phwnd = new IntPtr();
                    if ((shell.GetDialogOwnerHwnd(out phwnd) == 0) && (phwnd != new IntPtr()))
                    {
                        WindowInteropHelper helper = new WindowInteropHelper(this._dialog) {
                            Owner = phwnd
                        };
                    }
                    this._dialog.ShowInTaskbar = false;
                    this._dialog.ShowDialog();
                    bool flag2 = !this._dialog.DialogResult.HasValue ? false : this._dialog.DialogResult.Value;
                    this._dialog.Model = null;
                    if (!flag2)
                    {
                        throw new WizardCancelledException();
                    }
                    ContextViewModel currentContextViewModel = model.CurrentContextViewModel;
                    this._isClientAccessEnabled = (currentContextViewModel != null) && currentContextViewModel.IsClientAccessEnabled;
                    this._isODataEndpointEnabled = (currentContextViewModel != null) && currentContextViewModel.IsODataEndpointEnabled;
                    str5 = this.ComputeNamespace();
                    GeneratedCode code = model.GenerateBusinessLogicClass(str5);
                    replacementsDictionary.Add("$generatedcode$", code.SourceCode);
                    this.AddReferences(code.References);
                    this._businessLogicCode = code;
                    if (model.IsMetadataClassGenerationRequested)
                    {
                        GeneratedCode code2 = model.GenerateMetadataClasses(null);
                        replacementsDictionary.Add("$generatedmetadatacode$", code2.SourceCode);
                        this.AddReferences(code2.References);
                        this._generateMetadataFile = code2.SourceCode.Length > 0;
                        this._metadataCode = code2;
                    }
                    else
                    {
                        this._generateMetadataFile = false;
                    }
                }
            }
            finally
            {
                this._dialog = null;
            }
        }

        public bool ShouldAddProjectItem(string filePath)
        {
            return (!IsAssociatedMetadataFile(Path.GetFileName(filePath)) || this._generateMetadataFile);
        }

        private static bool ShouldCopyLocal(string assemblyReference)
        {
            return (File.Exists(assemblyReference) && assemblyReference.ToUpperInvariant().Contains(BusinessLogicClassConstants.LinqToSqlDomainServiceAssemblyName.ToUpperInvariant()));
        }

        public void ShowError(string errorMessage)
        {
            IUIService service = (IUIService) this.GetService(typeof(IUIService));
            if (service != null)
            {
                MessageBoxOptions options = 0;
                System.Windows.Forms.IWin32Window dialogOwnerWindow = service.GetDialogOwnerWindow();
                if (System.Threading.Thread.CurrentThread.CurrentUICulture.TextInfo.IsRightToLeft)
                {
                    options |= MessageBoxOptions.RightAlign;
                    options |= MessageBoxOptions.RtlReading;
                }
                MessageBox.Show(dialogOwnerWindow, errorMessage, Resources.WizardError_Caption, MessageBoxButtons.OK, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1, options);
            }
        }

        private void TerminateWizard(string errorMessage)
        {
            if (!string.IsNullOrEmpty(errorMessage))
            {
                this.ShowError(errorMessage);
                throw new WizardCancelledException(errorMessage);
            }
            throw new WizardCancelledException();
        }

        private void UpdateConfiguration()
        {
            if (this._isClientAccessEnabled || this._isODataEndpointEnabled)
            {
                Project activeProject = this.ActiveProject;
                IVsHierarchy vsHierarchy = this.GetVsHierarchy(activeProject);
                IVsApplicationConfigurationManager service = this.GetService(typeof(IVsApplicationConfigurationManager)) as IVsApplicationConfigurationManager;
                if (service == null)
                {
                    this.TerminateWizard(Resources.BusinessLogicClass_Error_No_ConfigurationManager);
                }
                using (IVsApplicationConfiguration configuration = service.GetApplicationConfiguration(vsHierarchy, 0xfffffffe))
                {
                    if ((configuration != null) && configuration.FileExists())
                    {
                        System.Configuration.Configuration configuration2 = configuration.LoadConfiguration();
                        if (configuration2 != null)
                        {
                            WebConfigUtil util = new WebConfigUtil(configuration2);
                            bool flag = util.DoWeNeedToAddHttpModule();
                            bool flag2 = util.DoWeNeedToAddModuleToWebServer();
                            bool flag3 = !util.IsAspNetCompatibilityEnabled();
                            bool flag4 = !util.IsMultipleSiteBindingsEnabled();
                            bool flag5 = util.DoWeNeedToValidateIntegratedModeToWebServer();
                            bool flag6 = this._isODataEndpointEnabled && !util.IsEndpointDeclared(BusinessLogicClassConstants.ODataEndpointName);
                            if (((flag || flag2) || (flag3 || flag4)) || (flag5 || flag6))
                            {
                                string domainServiceModuleTypeName = WebConfigUtil.GetDomainServiceModuleTypeName();
                                configuration.QueryEditConfiguration();
                                if (flag)
                                {
                                    util.AddHttpModule(domainServiceModuleTypeName);
                                }
                                if (flag2)
                                {
                                    util.AddModuleToWebServer(domainServiceModuleTypeName);
                                }
                                if (flag3)
                                {
                                    util.SetAspNetCompatibilityEnabled(true);
                                }
                                if (flag4)
                                {
                                    util.SetMultipleSiteBindingsEnabled(true);
                                }
                                if (flag5)
                                {
                                    util.AddValidateIntegratedModeToWebServer();
                                }
                                if (flag6)
                                {
                                    string oDataEndpointFactoryTypeName = WebConfigUtil.GetODataEndpointFactoryTypeName();
                                    util.AddEndpointDeclaration(BusinessLogicClassConstants.ODataEndpointName, oDataEndpointFactoryTypeName);
                                }
                                configuration2.Save();
                            }
                        }
                    }
                }
            }
        }

        private Project ActiveProject
        {
            get
            {
                if (this._project == null)
                {
                    Array activeSolutionProjects = (Array) this.DTE2.ActiveSolutionProjects;
                    this._project = activeSolutionProjects.OfType<Project>().FirstOrDefault<Project>();
                    if (this._project == null)
                    {
                        this.TerminateWizard(Resources.BusinessLogicClass_Error_No_Project);
                    }
                }
                return this._project;
            }
        }

        private EnvDTE80.DTE2 DTE2
        {
            get
            {
                if (this._dte2 == null)
                {
                    this.TerminateWizard(Resources.WizardError_No_DTE);
                }
                return this._dte2;
            }
        }

        internal InternalTestHook TestHook
        {
            get
            {
                if (this._testHook == null)
                {
                    this._testHook = new InternalTestHook(this);
                }
                return this._testHook;
            }
        }

        internal class InternalTestHook
        {
            private DomainServiceClassWizard _wizard;

            internal InternalTestHook(DomainServiceClassWizard wizard)
            {
                this._wizard = wizard;
            }

            internal Microsoft.VisualStudio.ServiceModel.DomainServices.Tools.BusinessLogicClassDialog BusinessLogicClassDialog
            {
                get
                {
                    return this._wizard._dialog;
                }
            }

            internal string GeneratedBusinessLogicCode
            {
                get
                {
                    return this._wizard._businessLogicCode.SourceCode;
                }
            }

            internal string GeneratedMetadataCode
            {
                get
                {
                    return this._wizard._metadataCode.SourceCode;
                }
            }
        }
    }
}

